﻿using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Interactivity;


namespace DailyFx.UI 
{

    /// <summary>
    ///		A collection that can exist as part of a behavior.
    /// </summary>
    public class AttachedCollection<T> : FreezableCollection<T>, IAttachedObject
        where T : DependencyObject, IAttachedObject
	{
        DependencyObject _associatedObject;

        /// <summary>
        ///		Creates an instance of <see cref="AttachedCollection{T}"/>
        /// </summary>
        public AttachedCollection() 
		{
            ((INotifyCollectionChanged)this).CollectionChanged += OnCollectionChanged;
        }

        /// <summary>
        /// Attached the collection.
        /// </summary>
        /// <param name="dependencyObject">The dependency object to attach the collection to.</param>
        public void Attach ( DependencyObject dependencyObject) 
		{
            WritePreamble();
				this._associatedObject = dependencyObject;
            WritePostscript();

            this.Apply( x => x.Attach(_associatedObject) );
        }

        /// <summary>
        ///		Detaches the collection.
        /// </summary>
        public void Detach() 
		{
            this.Apply( x => x.Detach() );

            WritePreamble();
				this._associatedObject = null;
            WritePostscript();
        }

        DependencyObject IAttachedObject.AssociatedObject
		{
            get { return this._associatedObject; }
        }

        /// <summary>
        ///		Called when an item is added to the collection.
        /// </summary>
        protected void OnItemAdded( T item ) 
		{
            if ( this._associatedObject != null)
                item.Attach( this._associatedObject );
        }

        /// <summary>
        ///		Called when an item is removed from the collection.
        /// </summary>
        protected void OnItemRemoved(T item)
		{
            if( item.AssociatedObject != null )
                item.Detach() ;
        }

		/// <summary>
		/// 
		/// </summary>
        void OnCollectionChanged ( object sender, NotifyCollectionChangedEventArgs e)
		{
            switch(e.Action) 
			{
                case NotifyCollectionChangedAction.Add:
                    e.NewItems.OfType<T>().Where(x => !Contains(x)).Apply(OnItemAdded);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    e.OldItems.OfType<T>().Apply(OnItemRemoved);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    e.OldItems.OfType<T>().Apply(OnItemRemoved);
                    e.NewItems.OfType<T>().Where(x => !Contains(x)).Apply(OnItemAdded);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    this.Apply(OnItemRemoved);
                    this.Apply(OnItemAdded);
                    break;
            }
        }
    }
}